package com.umfwechat.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;

/**
 * 加解密操作RSA
 * 
 * @author zhaohonglin
 * 
 * @version 1.0 2017-04-26
 * 
 */
public class DynamicCipher {

	static Logger logger = Logger.getLogger(DynamicCipher.class);

	private static String umpPriKeyPath = "pkcs8_safe_rsa_private_key.pem";
	private static String umpPubKeyPath = "pkcs8_safe_rsa_private_key.pem";

	//敏感字段解密私钥
	private static String umpPriKeySenstivePath = "pkcs8_safe_rsa_private_key_senstive.pem";
	public static String rsaDecrypt(byte[] info,String sense) throws Exception {
		
		InputStream is =null;
		if(sense.equals("sense"))
		{
			is = DynamicCipher.class.getClassLoader().getResourceAsStream(umpPriKeySenstivePath);
		}
		else{
			is = DynamicCipher.class.getClassLoader().getResourceAsStream(umpPriKeyPath);
		}
		
		byte[] priKey = loadUmpayPrivateKey(is);
		return rsaDecrypt(info, priKey);
	}

	// 私钥解密
	public static String rsaDecrypt(byte[] info, byte[] prikey) throws Exception {
		Cipher cipher = Cipher.getInstance(TRANSFORMATION_RSA, bc);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
		EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(prikey);
		PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] newPlainText = cipher.doFinal(info);
		return new String(newPlainText);
	}

	/*
	 * private static String umpPriKeyPath = "sercurity/MessageKey.pri"; private
	 * static String umpPubKeyPath = "sercurity/MessageKey.pub"; // openssl
	 * 秘钥证书路径 private static String umpPrivateKeyPath =
	 * "sercurity/openssl_rsa_private_key.pem"; private static String
	 * umpPublicKeyPath = "sercurity/openssl_rsa_public_key.pem";
	 */

	/*
	 * private static String umpPriKeyPath =
	 * "Users/Desktop/RSA_KEYS/openssl_rsa_private_key.key"; private static
	 * String umpPubKeyPath =
	 * "Users/Desktop/RSA_KEYS/openssl_rsa_public_key.key";
	 * 
	 * private static String RSApubPath="‪D:\\RSAKEYS\\public_key.pem"; private
	 * static String RSApriPath="D:\\RSAKEYS\\rsa_private_key_pkcs8.pem";
	 */
	// 读取私钥文件序列，程序中只用到了这个方法
	/*
	 * public static byte[] getUmpPriKeyBtye(){ return
	 * MyIO.readBinary(umpPriKeyPath); } public static String
	 * getUmpPriKeyBtye(String umpPriKeyPath) throws NoSuchAlgorithmException,
	 * InvalidKeySpecException, IOException { return
	 * readPKCS8PrivateKeyByte(umpPriKeyPath); } protected static String
	 * readPKCS8PrivateKeyByte(String path) throws IOException,
	 * NoSuchAlgorithmException, InvalidKeySpecException { //FileInputStream
	 * private_file_in = new FileInputStream(path); FileInputStream
	 * private_file_in = new
	 * FileInputStream("D:\\RSAKEYS\\rsa_private_key_pkcs8.pem"); byte
	 * pri_key_bs[] = new byte[private_file_in.available()];
	 * 
	 * int num=private_file_in.read(pri_key_bs); private_file_in.close(); return
	 * Util.bcd(pri_key_bs); }
	 * 
	 * //读取公钥文件序列 public static String getUmpPubKeyBtye() throws
	 * NoSuchAlgorithmException, InvalidKeySpecException, IOException{ return
	 * readX509PublicKeyByte(umpPubKeyPath); } public static String
	 * getUmpPubKeyBtye(String umpPubKeyPath) throws NoSuchAlgorithmException,
	 * InvalidKeySpecException, IOException{ return
	 * readX509PublicKeyByte(umpPubKeyPath); } protected static String
	 * readX509PublicKeyByte(String umpPubKeyPath) throws IOException,
	 * NoSuchAlgorithmException, InvalidKeySpecException{ //FileInputStream
	 * public_file_in = new FileInputStream(umpPubKeyPath); FileInputStream
	 * public_file_in = new FileInputStream("D:\\RSAKEYS\\public_key.pem"); byte
	 * pub_key_bs[] = new byte[public_file_in.available()];
	 * public_file_in.read(pub_key_bs); public_file_in.close(); return
	 * Util.bcd(pub_key_bs); }
	 */
	public static final String TRANSFORMATION_RSA = "RSA/ECB/PKCS1Padding";
	public static final String TRANSFORMATION_AES = "AES/ECB/PKCS5Padding";
	public static final String ALGORITHM_RSA = "RSA";
	private static final BouncyCastleProvider bc = new BouncyCastleProvider();

	// 公钥加密
	public static byte[] rsaEncrypt(byte[] info, byte[] pubkey)
			throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException {
		byte[] cipherText = null;
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA, bc);
		EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pubkey);
		PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
		// 进行公钥加密
		Cipher cipher = Cipher.getInstance(TRANSFORMATION_RSA);
		System.out.println("\n用公钥加密...");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		cipherText = cipher.doFinal(info); // 用公钥进行加密，返回一个字节流
		return cipherText;
	}

	// 公钥加密
	public static String rsaEncrypt(String plainText, byte[] pubkey) throws Exception {
		byte[] cipherText = null;
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA, bc);
		EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pubkey);
		PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
		// 进行公钥加密
		Cipher cipher = Cipher.getInstance(TRANSFORMATION_RSA);
		System.out.println("\n用公钥加密...");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		byte[] srcBytes = plainText.getBytes("GBK");
		cipherText = cipher.doFinal(srcBytes); // 用公钥进行加密，返回一个字节流
		return Base64.encode(cipherText);
	}

	/**
	 * 将二进制转换成16进制
	 * 
	 * @param b
	 * @return
	 */

	public static String bytesToHexStr(byte[] b) {

		String hs = "";

		String stmp = "";

		for (int n = 0; n < b.length; n++) {

			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));

			if (stmp.length() == 1)

				hs = hs + "0" + stmp;

			else

				hs = hs + stmp;

		}

		return hs.toUpperCase();

	}

	/**将16进制转换为二进制
	 * @param hexStr
	 * @return
	 */
	public static byte[] parseHexStr2Byte(String hexStr) {
		byte[] bytes;
		bytes = new byte[hexStr.length() / 2];
		for (int i = 0; i < bytes.length; i++) {
			bytes[i] = (byte) Integer.parseInt(hexStr.substring(2 * i, 2 * i + 2), 16);
		}
		return bytes;
	}

	public static byte[] hexStringToBytes(String hexString) {
		if (hexString == null || hexString.equals("")) {
			return null;
		}
		hexString = hexString.toUpperCase();
		int length = hexString.length() / 2;
		char[] hexChars = hexString.toCharArray();
		byte[] d = new byte[length];
		for (int i = 0; i < length; i++) {
			int pos = i * 2;
			d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
		}
		return d;
	}

	/** 
	 * Convert char to byte 
	 * @param c char 
	 * @return byte 
	 */
	private static byte charToByte(char c) {
		return (byte) "0123456789ABCDEF".indexOf(c);
	}

	protected static byte[] cipher(byte binfo[], byte bkey[], int mode, String transformation)
			throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
			BadPaddingException {
		String algs[] = transformation.split("/");
		SecretKey key = new SecretKeySpec(bkey, algs[0]);
		Cipher c1 = Cipher.getInstance(transformation);
		c1.init(mode, key);
		return c1.doFinal(binfo);
	}

	/**
	 * 解密
	 * 
	 * @param data 需要加密的内容
	 * @param aesKey  加密密码
	 * @return
	*/
	public static String aesDecrypt(byte[] aesKey, byte[] data) throws Exception {
		Cipher cipher = getAESCipher(aesKey, Cipher.DECRYPT_MODE);
		String aesData = new String(cipher.doFinal(data), "GBK");
		return aesData;
	}

	/**
	* 加密
	* 
	* @param data 需要解密的内容
	* @param aesKey  解密密码
	* @return
	*/
	public static byte[] aesEncrypt(byte[] aesKey, String data) throws Exception {
		Cipher cipher = getAESCipher(aesKey, Cipher.ENCRYPT_MODE);
		byte[] srcBytes = data.getBytes("GBK");
		// String aesData= Base64.encode(cipher.doFinal(srcBytes));
		return cipher.doFinal(srcBytes);
	}

	private static Cipher getAESCipher(byte[] byteKey, int mode) throws Exception {
		Cipher cipher = Cipher.getInstance(TRANSFORMATION_AES);
		SecretKeySpec skey = new SecretKeySpec(byteKey, "AES");
		cipher.init(mode, skey);
		return cipher;
	}

	/**
	 *  读取私钥文件序列
	 * desc:
	 * <p>创建人：umpay_zjk , 2015-7-28 下午2:38:37</p>
	 * @return
	 * @throws Exception
	 * 	String RSApubPath="‪D:\\RSAKEYS\\openssl_rsa_public_key.key";
	String RSApriPath="D:\\RSAKEYS\\openssl_rsa_private_key.key"; 
	 */
	public static byte[] loadUmpayPrivateKey(InputStream in) {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return loadUmpayPrivateKey(sb.toString()).getEncoded();
		} catch (Exception e) {
			e.printStackTrace();
//			throw new Exception("私钥数据读取错误");
		}finally {
			if(br != null){
				try {
					br.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 字符串中读取私钥文件
	 * desc:
	 * <p>创建人：umpay_zjk , 2015-7-28 下午2:38:44</p>
	 * @param privateKeyStr
	 * @return
	 * @throws Exception
	 */
	private static RSAPrivateKey loadUmpayPrivateKey(String privateKeyStr) throws Exception {
		try {
			BASE64Decoder base64Decoder = new BASE64Decoder();
			byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
			EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (Exception e) {
			throw new Exception("加载私钥证书时异常");
		}
	}

	/**
	 * 从文件中输入流中加载公钥
	 * desc:
	 * <p>创建人：umpay_zjk , 2015-7-28 下午2:45:51</p>
	 * @return
	 * @throws Exception
	 */
	public static byte[] loadUmpayPublicKey() throws Exception {
		try {
			File file = new File("D:\\RSAKEYS\\public_key.pem");
			// File file = new File(umpPubKeyPath);
			InputStream in = new FileInputStream(file);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return loadPublicKey(sb.toString()).getEncoded();
		} catch (Exception e) {
			throw new Exception("公钥数据流读取错误" + e);
		}
	}

	/**
	 * 从字符串中加载公钥
	 * @param publicKeyStr 公钥数据字符串
	 * @throws Exception 加载公钥时产生的异常
	 */
	private static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
		try {
			BASE64Decoder base64Decoder = new BASE64Decoder();
			byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			throw new Exception("公钥数据内容读取错误" + e);
		}
	}

	public static void main(String[] args) {

		System.out.println("===========");
		// InputStream is =
		// DynamicCipher.class.getClassLoader().getResourceAsStream("resources/safe_private.key");
		// System.out.println(is);

		/*
		 * //AES测试 String content = "d47d13b98f2e003074f81eb6f5a42806"; String
		 * password = "b9542df5 41e3ff"; //加密 System.out.println("加密前：" +
		 * password); byte[] encryptResult =
		 * aesEncrypt(DynamicCipher.parseHexStr2Byte(content),password); String
		 * encryptResultStr = bytesToHexStr(encryptResult);
		 * System.out.println("加密后：" + encryptResultStr); //解密 byte[]
		 * decryptFrom = parseHexStr2Byte(encryptResultStr); String
		 * decryptResult =
		 * aesDecrypt(DynamicCipher.parseHexStr2Byte(content),decryptFrom);
		 * System.out.println("解密后：" + decryptResult);
		 */

		// RSA测试‪
		/*
		 * String RSApubPath="‪D:\\RSAKEYS\\public_key.pem"; String
		 * RSApriPath="D:\\RSAKEYS\\openssl_rsa_private_key.key";
		 * 
		 * String publicKey=getUmpPubKeyBtye(RSApubPath); String
		 * privateKey=getUmpPriKeyBtye(RSApriPath);
		 * 
		 * byte[] privateKey=loadUmpayPrivateKey(); byte[] publicKey
		 * =loadUmpayPublicKey();
		 * 
		 * System.out.println("publicKey======================="+publicKey);
		 * //System.out.println("publicKey length======================="
		 * +publicKey.length());
		 * 
		 * System.out.println("privateKey======================="+privateKey);
		 * //System.out.println("privateKey length======================="
		 * +privateKey.length()); String key="abcdef123456";
		 * 
		 * // byte[] sercretKey=rsaEncrypt(key.getBytes(),Util.bcd(publicKey));
		 * byte[] sercretKey=rsaEncrypt(key.getBytes(),publicKey);
		 * System.out.println("sercretKey="+Util.bcd(sercretKey));
		 * System.out.println("sercretKey.len="+sercretKey.length); // String
		 * result=rsaDecrypt(sercretKey,Util.bcd(privateKey)); String
		 * result=rsaDecrypt(sercretKey,privateKey);
		 * System.out.println("result======================="+result);
		 * System.out.println("解密后result======================="+result);
		 */

	}
}
